App.require(["canvasTool", "htmlTool"], function (canvasTool, htmlTool) {
    var app = App.getCurrent();

    app.defineLayer("str-radar-chart", {
        render: function (next) {
            this.initProperty();
            this.data.isChange = true;
            this.data.isMouseIn = false;
            this.fetch("./index.html", function (text) {
                next(this.renderHTML(text));
            })
        },
        dispose: function () {
            this.removeAnimation();
            this.data.isChange = true;
            this.data.isMouseIn = false;
        },
        removeOption: function (index) {
            this.data.options.splice(index, 1);
            this.data.isChange = true;
            var property = this.property;
            if (property.animation) this.addPropertyAnimation(property.animation, this);
            else this.addChange();
        },
        appendOption: function (option) {
            this.data.options.push(option);
            this.data.isChange = true;
            var property = this.property;
            if (property.animation) this.addPropertyAnimation(property.animation, this);
            else this.addChange();
        },
        insertBefore: function (index, option) {
            this.data.options.splice(index, 0, option);
            this.data.isChange = true;
            var property = this.property;
            if (property.animation) this.addPropertyAnimation(property.animation, this);
            else this.addChange();
        },
        changeOption: function (index, opt) {
            var option = this.data.options[index];
            if (!option) return;
            this.data.isChange = true;
            this.addChange(opt, option);
        },
        initProperty: function () {
            var property = this.property;
            this.data.attributeStr = this._createPropertyStr(property);
            this.data.options = htmlTool.getOptions(this.slot);
            
            if (property.animation) this.addPropertyAnimation(property.animation, this);
        },
        get percent() {
            return this.getValue("percent");
        },
        set percent(value) {
            this.setValue("percent", value)
        },
        get steps() {
            return this.getValue("steps");
        },
        set steps(value) {
            this.setValue("steps", value);
        },
        get r() {
            return this.getValue("r");
        },
        set r(value) {
            this.setValue("r", value);
        },
        get helpfill() {
            return this.getValue("helpfill");
        },
        set helpfill(value) {
            this.setValue("helpfill", value);
        },
        get helpstroke() {
            return this.getValue("helpstroke");
        },
        set helpstroke(value) {
            this.setValue("helpstroke", value);
        },
        get startoffset() {
            return this.getValue("startoffset");
        },
        set startoffset(value) {
            this.setValue("startoffset", value);
        },
        get steps() {
            return this.getValue("steps");
        },
        set steps(value) {
            this.setValue("steps", value);
        },
        get fill() {
            return this.getValue("fill");
        },
        set fill(value) {
            this.setValue("fill", value);
        },
        get stroke() {
            return this.getValue("stroke");
        },
        set stroke(value) {
            this.setValue("stroke", value);
        },
        get linedash() {
            return this.getValue("linedash(");
        },
        set linedash(value) {
            this.setValue("linedash(", value);
        },
        get linedashoffset() {
            return this.getValue("linedashoffset");
        },
        set linedashoffset(value) {
            this.setValue("linedashoffset", value);
        },
        get linewidth() {
            return this.getValue("linewidth");
        },
        set linewidth(value) {
            this.setValue("linewidth", value);
        },
        get transform() {
            return this.getValue("transform");
        },
        set transform(value) {
            this.setValue("transform", value);
        },
        get shadow() {
            return this.getValue("shadow");
        },
        set shadow(value) {
            this.setValue("shadow", value);
        },
        get hidden() {
            return this.getValue("hidden");
        },
        set hidden(value) {
            this.setValue("hidden", value);
        },
        get x() {
            return this.getValue("x");
        },
        set x(value) {
            this.setValue("x", value);
        },
        get y() {
            return this.getValue("y");
        },
        set y(value) {
            this.setValue("y", value)
        },
        get mark() {
            return this.getValue("mark");
        },
        set mark(value) {
            this.setValue("mark", value)
        },
        transformView: function (ctx, ratio) {
           
            if (this.transform) {
                var tList = canvasTool.createTransformList(this.transform, ratio);
                for (var i = 0; i < tList.length; i++) {
                    var tObj = tList[i];
                    ctx[tObj.action].apply(ctx, tObj.args);
                }
            }
        },
        _getPoints: function (r, len, start, ratio) {
            start = start || 0;
            var result = [];
            for (var i = 0; i < len; i++) {
                var theta = 2 * Math.PI * i / len + start;
                result.push({ x: Math.cos(theta) * r * ratio, y: Math.sin(theta) * r * ratio});
            }
            return result;
        },
        _getRadiusPoints: function (obj, i, len, start, ratio, percent) {
            var value = parseFloat(obj.value) * ratio * percent;
            var theta = 2 * Math.PI * i / len + start;
            return {
                x: Math.cos(theta) * value, y: Math.sin(theta) * value
            }
        },
        moveLayerHandler: function (ev, ctx, ratio) {
            if (this.containsBounds(ctx, ev.clientX, ev.clientY, ratio)) {
                if (!this.data.isMouseIn) {
                    this.data.isMouseIn = true;
                    this.dispatchCustomEvent("radarchartmouseenter", {
                        component: this,
                        event: ev
                    });
                }
            }
            else {
                if (this.data.isMouseIn) {
                    this.data.isMouseIn = false;
                    this.dispatchCustomEvent("radarchartmouseleave", {
                        component: this,
                        event: ev
                    });
                }
            }
        },
        clickLayerHandler: function (ev, ctx, ratio) {
            if (this.containsBounds(ctx, ev.clientX, ev.clientY, ratio)) {
                this.dispatchCustomEvent("radarchartclick", {
                    component: this,
                    event: ev,
                });
            }
        },
        drawSelf: function (ctx, ratio) {
            var dObj = this.getPropertyUse(["percent", "steps", "r", "helpfill", "helpstroke", "x", "y", "startoffset", "steps", "linedash", "shadow", "linewidth", "linedashoffset", "fill", "stroke"]);
            var property = this.property, options = this.data.options;
            if (typeof dObj.opacity !== "undefined") ctx.globalAlpha = parseFloat(dObj.opacity);
            if (this.hidden || options.length == 0) return;
            ctx.translate(dObj.x * ratio, dObj.y * ratio);
            this.transformView(ctx, ratio);

            var start = dObj.startoffset, steps = dObj.steps;
            if (dObj.helpfill) {
                ctx.save();
                var fills = dObj.helpfill;
                for (var i = 0; i < steps; i++) {
                    var stepLen = dObj.r * i / steps, nextStepLen = dObj.r * (i + 1) / steps,
                        cps = this._getPoints(stepLen, options.length, start, ratio),
                        nps = this._getPoints(nextStepLen, options.length, start, ratio);

                    ctx.beginPath();
                    ctx.moveTo(cps[0].x, cps[0].y);
                    for (var j = 1; j < cps.length; j++) {
                        ctx.lineTo(cps[j].x, cps[j].y);
                    }
                    ctx.closePath();
                    ctx.moveTo(nps[0].x, nps[0].y);
                    for (var j = nps.length - 1; j >= 1; j--) {
                        ctx.lineTo(nps[j].x, nps[j].y);
                    }
                    ctx.closePath();
                    var fillStr = this._getStepColor(fills, i);
                    ctx.fillStyle = this.getFillOrStrokeStyle(fillStr);
                    ctx.fill();
                }
                ctx.restore();
            }
            var strokes = dObj.helpstroke;
            for (var i = 1; i <= steps; i++) {
                var stepLen = dObj.r * i / steps,
                    nps = this._getPoints(stepLen, options.length, start, ratio);

                ctx.beginPath();
                ctx.moveTo(nps[0].x, nps[0].y);
                for (var j = 1; j < nps.length; j++) {
                    ctx.lineTo(nps[j].x, nps[j].y);
                }
                ctx.closePath();
                var strokeStr = this._getStepColor(strokes, i);
                ctx.strokeStyle = this.getFillOrStrokeStyle(strokeStr);
                ctx.stroke();
            }

            var keyToCanvas = canvasTool.keyToCanvas;
            for (var key in property) {
                var ctxKey = keyToCanvas[key];
                if (ctxKey) {
                    if (ctxKey == "fillStyle" || ctxKey == "strokeStyle") continue;
                    else ctx[ctxKey] = dObj[key];
                }
            }

            if (dObj.linedash) this.useLineDash(ctx, dObj.linedash, dObj.linedashoffset, ratio);
            if (dObj.shadow) this.useShadow(ctx, dObj.shadow, ratio);

            var mk = this.marker, len = options.length, mark = this.mark, r = dObj.r;
            ctx.beginPath();
            for (var i = 0; i < options.length; i++) {
                var obj = options[i], p = this._getRadiusPoints(obj, i, len, start, ratio, dObj.percent);
                if (i == 0) ctx.moveTo(p.x, p.y);
                else ctx.lineTo(p.x, p.y);
            }
            ctx.closePath();
            ctx.save();
            if (dObj.fill) {
                ctx.fillStyle = this.getFillOrStrokeStyle(dObj.fill);
                ctx.fill();
            }
            if (dObj.stroke) {
                ctx.strokeStyle = this.getFillOrStrokeStyle(dObj.stroke);
                ctx.stroke();
            }
            ctx.restore();
            for (var i = 0; i < options.length; i++) {
                var obj = options[i], p = this._getRadiusPoints(obj, i, len, start, ratio, dObj.percent);
                if (mk || obj.marker) {
                    var marker = this.getMarkerByStr(obj.marker || mk, this, ratio);
                    if (marker) {
                        ctx.save();
                        ctx.translate(p.x + marker.offsetX, p.y + marker.offsetY);
                        marker.drawToCanvas(ctx, ratio);
                        ctx.restore();
                    }
                }

                if (mark) {
                    ctx.textAlign = obj.align || "center";
                    ctx.textBaseline = obj.baseline || "middle";
                    if (obj.font) ctx.font = this.computeFont(obj.font, ratio);
                    if (obj.textfill) ctx.fillStyle = this.getFillOrStrokeStyle(obj.textfill);
                    var offsetTextPos = this._getOffsetTextPos(ctx, obj, i, len, r, start, ratio);
                    ctx.fillText(obj.content, offsetTextPos.x, offsetTextPos.y);
                }
            }
        },
        createPath: function (ctx, ratio) {
            var options = this.data.options, len = options.length, property = this.property, start = this.startoffset;
            ctx.beginPath();
            for (var i = 0; i < options.length; i++) {
                var obj = options[i], p = this._getRadiusPoints(obj, i, len, start, ratio, this.percent);
                if (i == 0) ctx.moveTo(p.x, p.y);
                else ctx.lineTo(p.x, p.y);
            }
            ctx.closePath();
        },
        _getOffsetTextPos: function (ctx, obj, i, len, r, start, ratio) {
            var theta = 2 * Math.PI * i / len + start, r = r + 10, x = Math.cos(theta) * r * ratio, y = Math.sin(theta) * r * ratio;
            while (theta > Math.PI * 2 || theta < 0) {
                if (theta < 0) theta += Math.PI * 2;
                if (theta > Math.PI * 2) theta -= Math.PI * 2;
            }
            if (theta > 3 * Math.PI / 4 && theta < 5 * Math.PI / 4) {
                var width = ctx.measureText(obj.content).width;
                return { x: x - width / 2, y: y }
            }
            else if (theta > 7 * Math.PI / 4 || theta < Math.PI / 4) {
                var width = ctx.measureText(obj.content).width ;
                return { x: x + width / 2, y: y }
            }
            return {
                x: x, y: y
            }
        },
        _getStepColor: function (opts, i) {
            return opts[i % opts.length];
        },
    });
})